
{{#emitJSDoc}}
/**
 * The {{classname}} model module.
 * @module {{#invokerPackage}}{{.}}/{{/invokerPackage}}{{#modelPackage}}{{.}}/{{/modelPackage}}{{classname}}
 * @version {{projectVersion}}
 */
{{/emitJSDoc}}
class {{classname}} {
    {{#emitJSDoc}}/**
     * Constructs a new <code>{{classname}}</code>.{{#description}}
     * {{.}}{{/description}}
     * @alias module:{{#invokerPackage}}{{.}}/{{/invokerPackage}}{{#modelPackage}}{{.}}/{{/modelPackage}}{{classname}}
     * @param {{=< >=}}{(<#oneOf>module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><&.><^-last>|</-last></oneOf>)}<={{ }}=> instance The actual instance to initialize {{classname}}.
     */
    {{/emitJSDoc}}
    constructor(instance = null) {
        if (instance === null) {
            this.actualInstance = null;
            return;
        }
        var match = 0;
        var errorMessages = [];
        {{#composedSchemas.oneOf}}
        {{#description}}
        // {{{description}}}
        {{/description}}
        try {
            {{#isPrimitiveType}}
            {{#isArray}}
            // validate array data type
            if (!Array.isArray(instance)) {
                throw new Error("Invalid data type. Expecting array. Input: " + instance);
            }
            {{#minItems}}
            {{#maxItems}}
            if (instance.length > {{{maxItems}}} || instance.length < {{{minItems}}}) {
                throw new Error("Invalid array size. Minimim: {{minItems}}. Maximum: {{maxItems}}. Input: " + instance);
            }
            {{/maxItems}}
            {{^maxItems}}
            if (instance.length < {{{minItems}}}) {
                throw new Error("Invalid array size. Minimim: {{minItems}}. Input: " + instance);
            }
            {{/maxItems}}
            {{/minItems}}
            {{^minItems}}
            {{#maxItems}}
            if (instance.length > {{{maxItems}}}) {
                throw new Error("Invalid array size. Maximum: {{maxItems}}. Input: " + instance);
            }
            {{/maxItems}}
            {{/minItems}}
            {{#items.isInteger}}
            // validate array of integer
            for (const item of instance) {
                if (!(typeof item === 'number' && item % 1 === 0)) {
                    throw new Error("Invalid array items. Must be integer. Input: " + instance);
                }
                {{#items.maximum}}
                {{#items.minimum}}
                if (item > {{items.maximum}} || item < {{items.minimum}}) {
                    throw new Error("Invalid integer value in an array items. Max.: {{items.maximum}}. Min.: {{items.minimum}}. Input: " + instance);
                }
                {{/items.minimum}}
                {{^items.minimum}}
                if (item > {{items.maximum}}) {
                    throw new Error("Invalid integer value in an array items. Max.: {{items.maximum}}. Input: " + instance);
                }
                {{/items.minimum}}
                {{/items.maximum}}
                {{^items.maximum}}
                {{#items.minimum}}
                if (item < {{items.minimum}}) {
                    throw new Error("Invalid integer value in an array items. Min.: {{items.minimum}}. Input: " + instance);
                }
                {{/items.minimum}}
                {{/items.maximum}}
            }
            {{/items.isInteger}}
            {{#items.isString}}
            // validate array of string
            for (const item of instance) {
                if (!(typeof item === 'number' && item % 1 === 0)) {
                    throw new Error("Invalid array items. Must be string. Input: " + instance);
                }
                {{#items.pattern}}
                if (!{{{items.pattern}}}.test(item)) {
                    throw new Error("Invalid string value in an array items. Must conform to {{{items.pattern}}}. Input: " + item);
                }
                {{/items.pattern}}
                {{#items.minLength}}
                {{#items.maxLength}}
                if (item.length > {{items.maxLength}} && item.length < {{items.minLength}}) {
                    throw new Error("Invalid string value in an array items. Max. length: {{{items.maxLength}}}. Min. length: {{{items.minLength}}}. Input: " + item);
                }
                {{/items.maxLength}}
                {{^items.maxLength}}
                if (item.length < {{items.minLength}}) {
                    throw new Error("Invalid string value in an array items. Min. length: {{{items.minLength}}}. Input: " + item);
                }
                {{/items.maxLength}}
                {{/items.minLength}}
                {{^items.minLength}}
                {{#items.maxLength}}
                if (item.length > {{items.maxLength}}) {
                    throw new Error("Invalid string value in an array items. Max. length: {{{items.maxLength}}}. Input: " + item)
                }
                {{/items.maxLength}}
                {{/items.minLength}}
            }
            {{/items.isString}}
            {{#items.isNumber}}
            // validate array of number
            for (const item of instance) {
                if (!(typeof instance === 'number' && instance % 1 != 0)) {
                    throw new Error("Invalid array items. Must be number. Input: " + JSON.stringify(instance));
                }
            }
            {{/items.isNumber}}
            {{#items.isBoolean}}
            // validate array of boolean
            for (const item of instance) {
                if (!(typeof instance === 'boolean')) {
                    throw new Error("Invalid array items. Must be boolean. Input: " + JSON.stringify(instance));
                }
            }
            {{/items.isBoolean}}
            {{/isArray}}
            {{^isArray}}
            {{#isInteger}}
            // validate integer
            if (!(typeof instance === 'number' && instance % 1 === 0)) {
                throw new Error("Invalid value. Must be integer. Input: " + JSON.stringify(instance));
            }
            {{#maximum}}
            {{#minimum}}
            if (instance > {{maximum}} || instance < {{minimum}}) {
                throw new Error("Invalid integer value. Max.: {{maximum}}. Min.: {{minimum}}. Input: " + JSON.stringify(instance));
            }
            {{/minimum}}
            {{^minimum}}
            if (instance > {{maximum}}) {
                throw new Error("Invalid integer value. Max.: {{maximum}}. Input: " + JSON.stringify(instance));
            }
            {{/minimum}}
            {{/maximum}}
            {{^maximum}}
            {{#minimum}}
            if (instance < {{minimum}}) {
                throw new Error("Invalid integer value. Min.: {{minimum}}. Input: " + JSON.stringify(instance));
            }
            {{/minimum}}
            {{/maximum}}
            {{/isInteger}}
            {{#isString}}
            // validate string
            if (!(typeof instance === 'string')) {
                throw new Error("Invalid value. Must be string. Input: " + JSON.stringify(instance));
            }
            {{#pattern}}
            if (!{{{pattern}}}.test(instance)) {
                throw new Error("Invalid string value. Must conform to {{{.}}}. Input: " + JSON.stringify(instance));
            }
            {{/pattern}}
            {{#minLength}}
            {{#maxLength}}
            if (instance.length > {{maxLength}} && instance.length < {{minLength}}) {
                throw new Error("Invalid string value. Max. length: {{{maxLength}}}. Min. length: {{{minLength}}}. Input: " + JSON.stringify(instance));
            }
            {{/maxLength}}
            {{^maxLength}}
            if (instance.length < {{minLength}}) {
                throw new Error("Invalid string value. Min. length: {{{minLength}}}. Input: " + instance);
            }
            {{/maxLength}}
            {{/minLength}}
            {{^minLength}}
            {{#maxLength}}
            if (instance.length > {{maxLength}}) {
                throw new Error("Invalid string value in an array items. Max. length: {{{maxLength}}}. Input: " + JSON.stringify(instance));
            }
            {{/maxLength}}
            {{/minLength}}
            {{/isString}}
            {{#isNumber}}
            // validate number
            if (!(typeof instance === 'number' && instance % 1 != 0)) {
                throw new Error("Invalid value. Must be number. Input: " + JSON.stringify(instance));
            }
            {{/isNumber}}
            {{#isBoolean}}
            // validate boolean
            if (!(typeof instance === 'boolean')) {
                throw new Error("Invalid value. Must be boolean. Input: " + JSON.stringify(instance));
            }
            {{/isBoolean}}
            {{/isArray}}
            this.actualInstance = instance;
            {{/isPrimitiveType}}
            {{^isPrimitiveType}}
            if (typeof instance === "{{{dataType}}}") {
                this.actualInstance = instance;
            } else {
                // plain JS object
                // validate the object
                {{{dataType}}}.validateJSON(instance); // throw an exception if no match
                // create {{{dataType}}} from JS object
                this.actualInstance = {{{dataType}}}.constructFromObject(instance);
            }
            {{/isPrimitiveType}}
            match++;
        } catch(err) {
            // json data failed to deserialize into {{{dataType}}}
            errorMessages.push("Failed to construct {{{dataType}}}: " + err)
        }

        {{/composedSchemas.oneOf}}
        if (match > 1) {
            throw new Error("Multiple matches found constructing `{{{classname}}}` with oneOf schemas {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. Input: " + JSON.stringify(instance));
        } else if (match === 0) {
            this.actualInstance = null; // clear the actual instance in case there are multiple matches
            throw new Error("No match found constructing `{{{classname}}}` with oneOf schemas {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}. Details: " +
                            errorMessages.join(", "));
        } else { // only 1 match
            // the input is valid
        }
    }

    {{#emitJSDoc}}
    /**
     * Constructs a <code>{{classname}}</code> from a plain JavaScript object, optionally creating a new instance.
     * Copies all relevant properties from <code>data</code> to <code>obj</code> if supplied or a new instance if not.
     * @param {Object} data The plain JavaScript object bearing properties of interest.
     * @param {{=< >=}}{module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><classname>}<={{ }}=> obj Optional instance to populate.
     * @return {{=< >=}}{module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><classname>}<={{ }}=> The populated <code>{{classname}}</code> instance.
     */
    {{/emitJSDoc}}
    static constructFromObject(data, obj) {
        return new {{classname}}(data);
    }

    {{#emitJSDoc}}
    /**
     * Gets the actual instance, which can be {{#oneOf}}<code>{{{.}}}</code>{{^-last}}, {{/-last}}{{/oneOf}}.
     * @return {{=< >=}}{(<#oneOf>module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><&.><^-last>|</-last></oneOf>)}<={{ }}=> The actual instance.
     */
    {{/emitJSDoc}}
    getActualInstance() {
        return this.actualInstance;
    }

    {{#emitJSDoc}}
    /**
     * Sets the actual instance, which can be {{#oneOf}}<code>{{{.}}}</code>{{^-last}}, {{/-last}}{{/oneOf}}.
     * @param {{=< >=}}{(<#oneOf>module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><&.><^-last>|</-last></oneOf>)}<={{ }}=> obj The actual instance.
     */
    {{/emitJSDoc}}
    setActualInstance(obj) {
       this.actualInstance = {{classname}}.constructFromObject(obj).getActualInstance();
    }

    {{#emitJSDoc}}
    /**
     * Returns the JSON representation of the actual instance.
     * @return {string}
     */
    {{/emitJSDoc}}
    toJSON = function(){
        return this.getActualInstance();
    }

    {{#emitJSDoc}}
    /**
     * Create an instance of {{classname}} from a JSON string.
     * @param {string} json_string JSON string.
     * @return {{=< >=}}{module:<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><&classname>}<={{ }}=> An instance of {{classname}}.
     */
    {{/emitJSDoc}}
    static fromJSON = function(json_string){
        return {{classname}}.constructFromObject(JSON.parse(json_string));
    }
}

{{#vars}}{{#emitJSDoc}}/**{{#description}}
 * {{{.}}}{{/description}}
 * @member {{=< >=}}{<&vendorExtensions.x-jsdoc-type>}<={{ }}=> {{baseName}}{{#defaultValue}}
 * @default {{{.}}}{{/defaultValue}}
 */{{/emitJSDoc}}
{{classname}}.prototype['{{baseName}}'] = {{{defaultValue}}}{{^defaultValue}}undefined{{/defaultValue}};

{{/vars}}

{{classname}}.OneOf = [{{#oneOf}}"{{{.}}}"{{^-last}}, {{/-last}}{{/oneOf}}];

export default {{classname}};
